// ManagedBulkUsb.h

#pragma once

using namespace System;
using namespace System::Threading;
using namespace Microsoft::Robotics::Hardware::DAC;
using namespace System::Security;
using namespace System::Security::Permissions;

#include "DeviceAsyncEventArgs.h"

class DeviceInfo_t;

namespace Microsoft
{
	namespace Robotics
	{
		namespace ManagedBulkUsb {

			// Represents a WinUSB device
			public ref class Device : ITransport
			{
			public:
				/// <summary>
				/// Initializes a new instance of the <see cref="Device"/> class.
				/// </summary>
				/// <param name="deviceId">The device id.</param>
				Device(String^ deviceId);

				/// <summary>
				/// Disposes the device.
				/// </summary>
				~Device();

				/// <summary>
				/// Runs the finalizer.
				/// </summary>
				!Device();

				/// <summary>
				/// Connect to the device.
				/// </summary>
				virtual void Connect();

				/// <summary>
				/// Disconnect from the device.
				/// </summary>
				virtual void Disconnect();

				/// <summary>
				/// Create an operation that can be used (and reused) for
				/// reading and writing asynchronously on the device
				/// </summary>
				/// <param name="buffer">
				/// The buffer that will be used during async operations
				/// </param>
				/// <returns>The <see cref="AsyncEventArgs"/> instance</returns>
				virtual AsyncEventArgs^ PrepareAsyncOperation(array<Byte>^ buffer);

				/// <summary>
				/// Perform an asynchronous read
				/// </summary>
				/// <param name="eventArgs">The <see cref="AsyncEventArgs"/> async operation</param>
				/// <returns>
				/// <c>true</c> if the command completed synchronously, <c>false</c> otherwise.
				/// </returns>
				virtual Boolean AsyncRead(AsyncEventArgs^ eventArgs);

				/// <summary>
				/// Perform an asynchronous write
				/// </summary>
				/// <param name="eventArgs">The <see cref="AsyncEventArgs"/> async operation</param>
				/// <returns>
				/// <c>true</c> if the command completed synchronously, <c>false</c> otherwise.
				/// </returns>
				virtual Boolean AsyncWrite(AsyncEventArgs^ eventArgs);

			internal:
				// Get the result of an overlapped operation and populate it into the provided
				// eventArgs
				void    GetOverlappedResult(DeviceAsyncEventArgs^ eventArgs);

			private:
				// Issue a synchronous operation
				Int32   IssueSync(array<Byte>^ buffer, Int32 offset, Int32 count, AsyncOperation opType);

				// Issue an asynchronous operation
				Boolean IssueAsync(DeviceAsyncEventArgs^ eventArgs, AsyncOperation opType);

				// The device id
				String^ _deviceId;

				// An SRWLOCK used to protect the construction, disposal and use of the 
				// currently connected device
				PSRWLOCK _psrwLock;

				// A native structure used to hold the resources of the currently connected
				// device.
				DeviceInfo_t* _pdi;
			};
		}
	}
}
